home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / regedit / regmodul.bas < prev    next >
Encoding:
BASIC Source File  |  1995-10-17  |  41.5 KB  |  986 lines

  1. Attribute VB_Name = "REGMODUL"
  2. ' --------------------------------------------------------
  3. ' This .BAS module contains functions for reading and
  4. '   setting registry values in Windows 95 and Windows NT.
  5. '   The demo is in the form of a functional registry editor,
  6. '   although it is not meant to be a substitute for RegEdit
  7. '   or RegEdt32.  Declares are not provided
  8. '   for some rare registry functions, and not all functions
  9. '   have demo usage implemented.  Only values of type REG_SZ
  10. '   and REG_DWORD may be edited.
  11. '
  12. ' Written 10/95 by Don Bradner, based on code originally developed
  13. '   for VB3 using the CALL32 thunking file.  That file is not
  14. '   needed or used with this demo.  Requirements to run include
  15. '   VB4/32-bit, Windows 95 or NT 3.51 or later, and Comctl32.OCX,
  16. '   which comes with VB4 Pro or EE versions.
  17. '
  18. ' This material is placed in the public domain.  No guarantees
  19. '   are made, and no support is provided, but comments/bug
  20. '   reports are welcome to Don Bradner at Compuserve 76130,1007
  21. '   or at dbirdman@redshift.com.  Questions/comments are also
  22. '   welcome in the 32-bit section of the Visual Basic Programmer's
  23. '   Journal forum on Compuserve.
  24. '
  25. ' Warning:  Editing registry values can seriously impact your
  26. '   computer's operations.  You should only edit values when
  27. '   you know what they should be.  If editing values as a
  28. '   test, make a note of the original value and restore it
  29. '   when you are done.
  30. ' --------------------------------------------------------
  31.  
  32. Option Explicit
  33.  
  34. ' --------------------------------------------------------
  35. ' FILETIME type is needed for RegEnumKey and
  36. '   RegQueryInfoKey
  37. ' --------------------------------------------------------
  38. Type FILETIME
  39.     lLowDateTime    As Long
  40.     lHighDateTime   As Long
  41. End Type
  42.  
  43. ' --------------------------------------------------------
  44. ' OsVersionInfo type is needed for GetVersionEx
  45. ' --------------------------------------------------------
  46. Type OsVersionInfo
  47.     dwVersionInfoSize As Long
  48.     dwMajorVersion As Long
  49.     dwMinorVersion As Long
  50.     dwBuildNumber As Long
  51.     dwPlatform As Long
  52.     szCSDVersion As String * 128
  53. End Type
  54.  
  55. Public RegEntry As New RegistryEntry
  56.  
  57. ' ---------------------------
  58. ' 32-bit registry functions
  59. ' ---------------------------
  60. Declare Function RegOpenKeyEx& Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey&, ByVal lpszSubKey$, dwOptions&, ByVal samDesired&, lpHKey&)
  61. Declare Function RegCloseKey& Lib "advapi32.dll" (ByVal hKey&)
  62. Declare Function RegQueryValueEx& Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey&, ByVal lpszValueName$, ByVal lpdwRes&, lpdwType&, ByVal lpDataBuff$, nSize&)
  63. Declare Function RegSetValueEx& Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey&, ByVal lpszValueName$, ByVal dwRes&, ByVal dwType&, lpDataBuff As Any, ByVal nSize&)
  64. Declare Function RegConnectRegistry& Lib "advapi32.dll" (ByVal lpMachineName$, ByVal hKey&, phkResult&)
  65. Declare Function RegCreateKeyEx& Lib "advapi32.dll" Alias "RegCreateKeyExA" (ByVal hKey&, ByVal lpSubKey$, ByVal Reserved&, ByVal lpClass$, ByVal dwOptions&, ByVal samDesired&, lpSecurityAttributes&, phkResult&, lpdwDisposition&)
  66. Declare Function RegFlushKey& Lib "advapi32.dll" (ByVal hKey&)
  67. Declare Function RegEnumKeyEx& Lib "advapi32.dll" Alias "RegEnumKeyExA" (ByVal hKey&, ByVal dwIndex&, ByVal lpName$, lpcbName&, ByVal lpReserved&, ByVal lpClass$, lpcbClass&, lpftLastWriteTime As FILETIME)
  68. Declare Function RegEnumValue& Lib "advapi32.dll" Alias "RegEnumValueA" (ByVal hKey&, ByVal dwIndex&, ByVal lpName$, lpcbName&, ByVal lpReserved&, lpdwType&, lpValue As Any, lpcbValue&)
  69. Declare Function RegQueryInfoKey& Lib "advapi32.dll" Alias "RegQueryInfoKeyA" (ByVal hKey&, ByVal lpClass$, lpcbClass&, ByVal lpReserved&, lpcSubKeys&, lpcbMaxSubKeyLen&, lpcbMaxClassLen&, lpcValues&, lpcbMaxValueNameLen&, lpcbMaxValueLen&, lpcbSecurityDescriptor&, lpftLastWriteTime As FILETIME)
  70.  
  71. Declare Function GetVersionEx& Lib "kernel32.dll" Alias "GetVersionExA" (lpStruct As OsVersionInfo)
  72.  
  73. ' --------------------------------------------------------
  74. ' Functions used to show hourglass
  75. ' --------------------------------------------------------
  76. Declare Function LoadCursor& Lib "User32" Alias "LoadCursorA" (ByVal hInstance&, ByVal lpCursor&)
  77. Declare Function SetCursor& Lib "User32" (ByVal hCursor&)
  78. Public Const IDC_WAIT = 32514&
  79.  
  80. Public iWaitCursor&
  81.  
  82. Public lNewKey& 'used to generate unique Node keys
  83.  
  84. ' --------------------------------------------------------
  85. ' Return codes from Registration functions.
  86. ' --------------------------------------------------------
  87. Const ERROR_SUCCESS = 0&
  88. Const ERROR_BADDB = 1009&
  89. Const ERROR_BADKEY = 1010&
  90. Const ERROR_CANTOPEN = 1011&
  91. Const ERROR_CANTREAD = 1012&
  92. Const ERROR_CANTWRITE = 1013&
  93. Const ERROR_OUTOFMEMORY = 14&
  94. Const ERROR_INVALID_PARAMETER = 87&
  95. Const ERROR_ACCESS_DENIED = 5&
  96. Const ERROR_NO_MORE_ITEMS = 259&
  97. Const ERROR_MORE_DATA = 234&
  98.  
  99. Public Const HKEY_CLASSES_ROOT = &H80000000
  100. Public Const HKEY_CURRENT_USER = &H80000001
  101. Public Const HKEY_LOCAL_MACHINE = &H80000002
  102. Public Const HKEY_USERS = &H80000003
  103. Public Const HKEY_PERFORMANCE_DATA = &H80000004
  104. Public Const HKEY_CURRENT_CONFIG = &H80000005
  105. Public Const HKEY_DYN_DATA = &H80000006
  106.    
  107. Public Const LB_SETHORIZONTALEXTENT = &H400 + 21
  108.  
  109. Const REG_NONE = 0&                        ' No value type
  110. Public Const REG_SZ = 1&                   ' Unicode nul terminated string
  111. Const REG_EXPAND_SZ = 2&                   ' Unicode nul terminated string
  112.                                            ' (with environment variable references)
  113. Const REG_BINARY = 3&                      ' Free form binary
  114. Public Const REG_DWORD = 4&                ' 32-bit number
  115. Const REG_DWORD_LITTLE_ENDIAN = 4&         ' 32-bit number (same as REG_DWORD)
  116. Const REG_DWORD_BIG_ENDIAN = 5&            ' 32-bit number
  117. Const REG_LINK = 6&                        ' Symbolic Link (unicode)
  118. Const REG_MULTI_SZ = 7&                    ' Multiple Unicode strings
  119. Const REG_RESOURCE_LIST = 8&               ' Resource list in the resource map
  120. Const REG_FULL_RESOURCE_DESCRIPTOR = 9&    ' Resource list in the hardware description
  121. Const REG_RESOURCE_REQUIREMENTS_LIST = 10&
  122.  
  123.  
  124. ' --------------------------------------------------------
  125. ' Read/Write permissions:
  126. ' --------------------------------------------------------
  127. Const KEY_QUERY_VALUE = &H1&
  128. Const KEY_SET_VALUE = &H2&
  129. Const KEY_CREATE_SUB_KEY = &H4&
  130. Const KEY_ENUMERATE_SUB_KEYS = &H8&
  131. Const KEY_NOTIFY = &H10&
  132. Const KEY_CREATE_LINK = &H20&
  133. Const READ_CONTROL = &H20000
  134. Const WRITE_DAC = &H40000
  135. Const WRITE_OWNER = &H80000
  136. Const SYNCHRONIZE = &H100000
  137. Const STANDARD_RIGHTS_REQUIRED = &HF0000
  138. Const STANDARD_RIGHTS_READ = READ_CONTROL
  139. Const STANDARD_RIGHTS_WRITE = READ_CONTROL
  140. Const STANDARD_RIGHTS_EXECUTE = READ_CONTROL
  141. Const KEY_READ = STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY
  142. Const KEY_WRITE = STANDARD_RIGHTS_WRITE Or KEY_SET_VALUE Or KEY_CREATE_SUB_KEY
  143. Const KEY_EXECUTE = KEY_READ
  144.  
  145.  
  146. ' --------------------------------------------------------
  147. ' Used with GetVersionEX
  148. ' --------------------------------------------------------
  149. Public iWinVers%
  150. Public Const WinNt = 1
  151. Public Const Win32 = 2
  152.  
  153. Public Const VER_PLATFORM_WIN32_WINDOWS = 1
  154. Public Const VER_PLATFORM_WIN32_NT = 2
  155.  
  156.  
  157. ' --------------------------------------------------------
  158. ' Public program variables
  159. ' --------------------------------------------------------
  160. Public lTempLong&
  161. Public fTempDbl#
  162. Public sTempString$
  163.  
  164.  
  165. Sub CenterForm(FormName As Form)
  166.     FormName.Move (Screen.Width - FormName.Width) / 2, (Screen.Height - FormName.Height) / 2
  167. End Sub
  168.  
  169. Sub EditRegValue(ByVal nodX As Node, lRegIndex&)
  170.     ' --------------------------------------------------------
  171.     ' Specific to the RegDemo application.
  172.     ' --------------------------------------------------------
  173.     RegEntry.rgeSubKey = nodX.FullPath
  174.     RegEntry.rgeSubKey = Right$(RegEntry.rgeSubKey, Len(RegEntry.rgeSubKey) - 12)
  175.     If InStr(RegEntry.rgeSubKey, "\") = 0 Then
  176.         RegEntry.rgeMainKey = GetMainKey(RegEntry.rgeSubKey)
  177.         RegEntry.rgeSubKey = ""
  178.     Else
  179.         '-------------------------------------------------
  180.         'This must be a SubKey.
  181.         '-------------------------------------------------
  182.         RegEntry.rgeMainKey = GetMainKey(Left$(RegEntry.rgeSubKey, InStr(RegEntry.rgeSubKey, "\") - 1))
  183.         RegEntry.rgeSubKey = Right$(RegEntry.rgeSubKey, Len(RegEntry.rgeSubKey) - InStr(RegEntry.rgeSubKey, "\"))
  184.     End If
  185.  
  186.     Dim lRtn&       ' Returned by registry functions, should be 0&
  187.     Dim hKey&       ' Return handle to opened key
  188.     Dim lLenValueName&
  189.     Dim lLenValue&
  190.     Dim lKeyIndx&
  191.    
  192.     ' --------------------------------------------------------
  193.     ' values for QueryInfoKey:
  194.     ' --------------------------------------------------------
  195.     Dim sClassName$
  196.     Dim lClassLen&
  197.     Dim lSubKeys&
  198.     Dim lMaxSubKey&
  199.     Dim lMaxClass&
  200.     Dim lValues&
  201.     Dim lMaxValueName&
  202.     Dim lMaxValueData&
  203.     Dim lSecurityDesc&
  204.     Dim strucLastWriteTime As FILETIME
  205.     
  206.     ' -----------------------------------------------------
  207.     ' Open key
  208.     ' -----------------------------------------------------
  209.     lRtn = RegOpenKeyEx(RegEntry.rgeMainKey, RegEntry.rgeSubKey, 0&, KEY_READ, hKey)
  210.     If lRtn <> ERROR_SUCCESS Then
  211.         MsgBox RtnRegError(lRtn)
  212.       
  213.         ' --------------------------------------------------
  214.         ' No key open, so leave
  215.         ' --------------------------------------------------
  216.         Exit Sub
  217.     End If
  218.     
  219.     ' -----------------------------------------------------
  220.     ' RegQueryInfoKey is used to get the size of the largest
  221.     '   value name and data string.
  222.     ' Other returned values are ignored.
  223.     ' -----------------------------------------------------
  224.     sClassName = Space$(255) 'initialize these because occasional errors otherwise
  225.     lClassLen = CLng(Len(sClassName))
  226.     lRtn = RegQueryInfoKey(hKey, sClassName, lClassLen, 0&, lSubKeys, lMaxSubKey, lMaxClass, lValues, lMaxValueName, lMaxValueData, lSecurityDesc, strucLastWriteTime)
  227.  
  228.     '-------------------------------------------------------------------
  229.     'If the enumeration fails due to a buffer over-run, we will loop back
  230.     'to this point with larger buffers.
  231.     '-------------------------------------------------------------------
  232. RetryValueHere:
  233.     
  234.     ' --------------------------------------------------
  235.     ' Set variables
  236.     ' --------------------------------------------------
  237.     RegEntry.rgeEntry = Space$(lMaxValueName + 1)
  238.     lLenValueName = CLng(Len(RegEntry.rgeEntry)) '+ 1
  239.     RegEntry.rgeValue = Space$(lMaxValueData + 1)
  240.     lLenValue = CLng(Len(RegEntry.rgeValue))       '+ 1
  241.     
  242.     ' --------------------------------------------------
  243.     ' Call the enumeration function to get the indexed value
  244.     ' --------------------------------------------------
  245.     lRtn = RegEnumValue(hKey, lRegIndex, RegEntry.rgeEntry, lLenValueName, 0&, RegEntry.rgeDataType, ByVal RegEntry.rgeValue, lLenValue)
  246.     
  247.     
  248.     ' --------------------------------------------------
  249.     ' Check for success
  250.     ' --------------------------------------------------
  251.     If lRtn = ERROR_SUCCESS Then
  252.         If RegEntry.rgeDataType <> REG_SZ And RegEntry.rgeDataType <> REG_DWORD Then
  253.             
  254.             '--------------------------------------------------------------
  255.             'Tell us what value types may be edited, along with
  256.             '    the type of value found.
  257.             '--------------------------------------------------------------
  258.             sTempString = "This Demo only supports editing of values with types of REG_SZ and REG_DWORD.  This value is of type "
  259.             Select Case RegEntry.rgeDataType
  260.                 Case 2
  261.                     sTempString = sTempString & "REG_EXPAND_SZ."
  262.                 Case 3
  263.                     sTempString = sTempString & "REG_BINARY."
  264.                 Case 5
  265.                     sTempString = sTempString & "REG_DWORD_BIG_ENDIAN."
  266.                 Case 6
  267.                     sTempString = sTempString & "REG_LINK."
  268.                 Case 7
  269.                     sTempString = sTempString & "REG_MULTI_SZ."
  270.                 Case 8
  271.                     sTempString = sTempString & "REG_RESOURCE_LIST."
  272.                 Case 9
  273.                     sTempString = sTempString & "REG_FULL_RESOURCE_DESCRIPTOR."
  274.                 Case 10
  275.                     sTempString = sTempString & "REG_RESOURCE_REQUIREMENTS_LIST."
  276.             End Select
  277.             MsgBox sTempString
  278.  
  279.         Else
  280.             RegEntry.rgeEntry = Mid$(RegEntry.rgeEntry, 1, lLenValueName)
  281.             If lLenValueName = 0 Then
  282.                 RegEntry.rgeEntry = "(Default)"
  283.             End If
  284.             RegEntry.rgeValue = Mid$(RegEntry.rgeValue, 1, lLenValue)
  285.             ' --------------------------------------------
  286.             ' Convert DWORD 4 character value to 32-bit
  287.             '   number.
  288.             ' First character is low byte, and so on.
  289.             ' --------------------------------------------
  290.             Form2.Caption = "Edit String Value"
  291.             If RegEntry.rgeDataType = REG_DWORD Then
  292.                 fTempDbl = Asc(Mid$(RegEntry.rgeValue, 1, 1)) + &H100& * Asc(Mid$(RegEntry.rgeValue, 2, 1)) + &H10000 * Asc(Mid$(RegEntry.rgeValue, 3, 1)) + &H1000000 * CDbl(Asc(Mid$(RegEntry.rgeValue, 4, 1)))
  293.                 If fTempDbl > &H7FFFFFFF Then
  294.                     RegEntry.rgeValue = Hex$(fTempDbl - 4294967296#)
  295.                 Else
  296.                     RegEntry.rgeValue = Hex$(fTempDbl)
  297.                 End If
  298.                 ' -----------------------------------------
  299.                 ' Turn on Hex/Decimal options
  300.                 ' -----------------------------------------
  301.                 Form2!Frame1.Visible = True
  302.                 Form2.Caption = "Edit DWORD Value"
  303.             End If
  304.             
  305.             ' --------------------------------------------
  306.             ' Place the values in the form2 text boxes
  307.             ' --------------------------------------------
  308.             Form2!Text1 = RegEntry.rgeEntry
  309.             Form2!text2 = RegEntry.rgeValue
  310.         
  311.             ' --------------------------------------------
  312.             ' Pass the key variables to form2 via hidden
  313.             '   text boxes
  314.             ' --------------------------------------------
  315.             Form2.Show 1
  316.         End If
  317.  
  318.     ElseIf lRtn = ERROR_MORE_DATA Then
  319.         ' -----------------------------------------------
  320.         ' This error means that, despite querying the key
  321.         '   we have not set one of the buffers large
  322.         '   enough. If the buffer is already 20000 we are
  323.         '   not going to be able to edit it.
  324.         ' -----------------------------------------------
  325.         If lMaxValueData >= 20000 Then
  326.             MsgBox ("Value is too large for this editor!")
  327.         Else
  328.         
  329.             ' --------------------------------------------
  330.             ' Increase the buffer sizes and try again
  331.             ' --------------------------------------------
  332.             lMaxValueData = lMaxValueData + 5
  333.             lMaxValueName = lMaxValueName + 5
  334.             GoTo RetryValueHere
  335.         End If
  336.     Else
  337.         
  338.         ' --------------------------------------------------
  339.         ' Key still open, so display the error and fall
  340.         '   thru to the close function below
  341.         ' --------------------------------------------------
  342.         MsgBox RtnRegError(lRtn)
  343.     End If
  344.  
  345.     ' -----------------------------------------------------
  346.     ' Always close opened keys!
  347.     ' -----------------------------------------------------
  348.     lRtn = RegCloseKey(hKey)
  349.  
  350. End Sub
  351.  
  352.  
  353. Function GetMainKey&(keyname$)
  354.    
  355.    ' -----------------------------------------------------
  356.    ' Used to convert main key strings to their values
  357.    ' -----------------------------------------------------
  358.  
  359.     Select Case keyname
  360.         Case "HKEY_CLASSES_ROOT"
  361.             GetMainKey = HKEY_CLASSES_ROOT
  362.         Case "HKEY_CURRENT_USER"
  363.             GetMainKey = HKEY_CURRENT_USER
  364.         Case "HKEY_LOCAL_MACHINE"
  365.             GetMainKey = HKEY_LOCAL_MACHINE
  366.         Case "HKEY_USERS"
  367.             GetMainKey = HKEY_USERS
  368.         Case "HKEY_PERFORMANCE_DATA"
  369.             GetMainKey = HKEY_PERFORMANCE_DATA
  370.         Case "HKEY_CURRENT_CONFIG"
  371.             GetMainKey = HKEY_CURRENT_CONFIG
  372.         Case "HKEY_DYN_DATA"
  373.             GetMainKey = HKEY_DYN_DATA
  374.     End Select
  375.  
  376. End Function
  377.  
  378.  
  379. Function RegEnumKeys&(ByVal Node As Node, bFullEnumeration As Boolean)
  380.     lTempLong = SetCursor(iWaitCursor)
  381.     Dim sRoot$
  382.     
  383.     '-------------------------------------------------------------
  384.     'Because we will recurse this function we need to make a
  385.     'separate instance of RegistryEntry to avoid altering a
  386.     'global property.
  387.     '-------------------------------------------------------------
  388.     Dim RegEnumEntry As New RegistryEntry
  389.     RegEnumEntry.rgeSubKey = Node.FullPath
  390.     If RegEnumEntry.rgeSubKey = "My Computer" Then Exit Function
  391.         '---------------------------------------------
  392.     'If we've put in a single key to set the + image,
  393.     'remove that key to avoid duplication
  394.     '---------------------------------------------
  395.     While Node.Children > 0
  396.         Form1!TreeView1.Nodes.Remove Node.Child.Key
  397.     Wend
  398.     RegEnumEntry.rgeExtractKeys
  399.     sRoot = Node.Key
  400. ' --------------------------------------------------------
  401.     ' This function will load all subkeys into the TreeView
  402.     '   iLevels tells us how far to indent, while
  403.     '   iStartList tells us where we are in the TreeView
  404.     ' --------------------------------------------------------
  405.     Dim lRtn&       ' Returned by registry functions, should be 0&
  406.     Dim hKey&       ' Return handle to opened key
  407.     Dim strucLastWriteTime    As FILETIME
  408.     Dim sSubKeyName$
  409.     Dim sClassString$
  410.     Dim lLenSubKey&
  411.     Dim lLenClass&
  412.     Dim lKeyIndx&
  413.     Dim lRet&
  414.     Dim hKey2&
  415.     Dim sSubKey2$
  416.     Dim nodX As Node
  417.     Dim sNewKey$
  418.     
  419.     '---------------------------------------------
  420.     'values for QueryInfoKey:
  421.     '---------------------------------------------
  422.     Dim sClassName$
  423.     Dim lClassLen&
  424.     Dim lSubKeys&
  425.     Dim lMaxSubKey&
  426.     Dim lMaxClass&
  427.     Dim lMaxSubKey2&  'Used for second QueryInfoKey in loop
  428.     Dim lMaxClass2&   'Same
  429.     Dim lValues&
  430.     Dim lMaxValueName&
  431.     Dim lMaxValueData&
  432.     Dim lSecurityDesc&
  433.     
  434.     ' -----------------------------------------------------
  435.     ' Open key
  436.     ' -----------------------------------------------------
  437.     lRtn = RegOpenKeyEx(RegEnumEntry.rgeMainKey, RegEnumEntry.rgeSubKey, 0&, KEY_READ, hKey)
  438.     If lRtn <> ERROR_SUCCESS Then
  439.         If lRtn = ERROR_ACCESS_DENIED Then
  440.             '---------------------------------------------
  441.             'Grey the key
  442.             'otherwise report error condition
  443.             '---------------------------------------------
  444.             Node.Image = 6
  445.             'Node.Enabled = False 'Doesn't work?
  446.         Else
  447.             MsgBox RtnRegError(lRtn)
  448.         End If
  449.         RegEnumKeys = lRtn
  450.         Exit Function
  451.         
  452.         ' --------------------------------------------------
  453.         ' No key open, so leave
  454.         ' --------------------------------------------------
  455.     End If
  456.     
  457.     ' -----------------------------------------------------
  458.     ' A call to RegQueryInfoKey will tell us the maximum
  459.     '   keyname length
  460.     ' -----------------------------------------------------
  461.     sClassName = Space$(255)
  462.     lClassLen = CLng(Len(sClassName))
  463.     lRet = RegQueryInfoKey(hKey, sClassName, lClassLen, 0&, lSubKeys, lMaxSubKey, lMaxClass, lValues, lMaxValueName, lMaxValueData, lSecurityDesc, strucLastWriteTime)
  464.  
  465.     ' -----------------------------------------------------
  466.     ' Enumerate the keys
  467.     ' -----------------------------------------------------
  468.     lKeyIndx = 0&
  469.     Do While lRtn = ERROR_SUCCESS
  470.         
  471.         ' -----------------------------------------------------
  472.         ' If the enumeration fails due to a buffer over-run,
  473.         '   we will loop back to this point with larger buffers.
  474.         ' -----------------------------------------------------
  475. ReTryKeyEnumeration:
  476.             
  477.         ' --------------------------------------------------
  478.         ' Set variables
  479.         ' --------------------------------------------------
  480.         sSubKeyName = Space$(lMaxSubKey + 1)
  481.         lLenSubKey = CLng(Len(sSubKeyName))
  482.         sClassString = Space$(lMaxClass + 1)
  483.         lLenClass = CLng(Len(sClassString))
  484.     
  485.         
  486.         ' --------------------------------------------------
  487.         ' Call the enumeration function
  488.         ' --------------------------------------------------
  489.         lRtn = RegEnumKeyEx(hKey, lKeyIndx, sSubKeyName, lLenSubKey, 0&, sClassString, lLenClass, strucLastWriteTime)
  490.         If InStr(sSubKeyName, Chr$(0)) > 1 Then
  491.             sSubKeyName = Left$(sSubKeyName, InStr(sSubKeyName, Chr$(0)) - 1)
  492.         End If
  493.         
  494.         
  495.         ' --------------------------------------------------
  496.         ' Check for success
  497.         ' --------------------------------------------------
  498.         If lRtn = ERROR_SUCCESS Then
  499.             sSubKey2 = sSubKeyName
  500.             If RegEnumEntry.rgeSubKey <> "" Then
  501.                 sSubKey2 = Trim(RegEnumEntry.rgeSubKey) & "\" & sSubKeyName
  502.              End If
  503.  
  504.             ' -----------------------------------------------
  505.             ' Use RegQueryInfoKey to find out if this key has
  506.             '   subkeys
  507.             ' -----------------------------------------------
  508.             lRet = RegOpenKeyEx(RegEnumEntry.rgeMainKey, sSubKey2, 0&, KEY_READ, hKey2)
  509.             lNewKey = lNewKey + 1
  510.             sNewKey = "A" & Format$(lNewKey, "000000")
  511.             Set nodX = Form1!TreeView1.Nodes.Add(sRoot, tvwChild, sNewKey, sSubKeyName, 1)
  512.             If bFullEnumeration = True Then
  513.                 '------------------------------------------------------
  514.                 'We are fully enumerating a key, so set images and
  515.                 'Recurse a single SubKey to set + indicator if there are
  516.                 'subkeys below this one
  517.                 '------------------------------------------------------
  518.                 lRet = RegEnumKeys(nodX, False)
  519.                 If lRet = ERROR_ACCESS_DENIED Then
  520.                     nodX.ExpandedImage = 6
  521.                     nodX.SelectedImage = 6
  522.                 Else
  523.                     nodX.ExpandedImage = 2
  524.                     nodX.SelectedImage = 2
  525.                 End If
  526.             Else
  527.                 Exit Do
  528.             End If
  529.             lKeyIndx = lKeyIndx + 1
  530.         ElseIf lRtn = ERROR_MORE_DATA Then
  531.             ' -----------------------------------------------
  532.             ' This error means that, despite querying the key
  533.             '   we have not set one of the buffers large
  534.             '   enough.Increment the buffer sizes and try
  535.             '   again
  536.             ' -----------------------------------------------
  537.             lMaxSubKey = lMaxSubKey + 5
  538.             lMaxClass = lMaxClass + 5
  539.             GoTo ReTryKeyEnumeration
  540.         ElseIf lRtn = ERROR_NO_MORE_ITEMS Then
  541.             ' -----------------------------------------------
  542.             ' Not an error, just end of list -- exit the
  543.             '   loop
  544.             ' -----------------------------------------------
  545.             lRtn = ERROR_SUCCESS
  546.             Exit Do
  547.         ElseIf lRtn <> ERROR_SUCCESS Then
  548.             ' --------------------------------------------------
  549.             ' Key still open, so display the error and fall
  550.             '   thru to the close function below
  551.             ' --------------------------------------------------
  552.             MsgBox RtnRegError(lRtn)
  553.             Exit Do
  554.         End If
  555.     Loop
  556.  
  557.     
  558.     ' -----------------------------------------------------
  559.     ' Set the return to the last error
  560.     ' -----------------------------------------------------
  561.     RegEnumKeys = lRtn
  562.     Set RegEnumEntry = Nothing
  563.  
  564.     ' -----------------------------------------------------
  565.     ' Always close opened keys!
  566.     ' -----------------------------------------------------
  567.     lRtn = RegCloseKey(hKey)
  568.  
  569. End Function
  570. Public Sub RegEnumValues()
  571.     ' --------------------------------------------------------
  572.     'Enter with RegEntry.rgeSubKey containing a full key path, in
  573.     'My Computer\HKEY_..\..\ fashion
  574.     ' --------------------------------------------------------
  575.     Dim lRtn&        ' Returned by registry functions, should be 0&
  576.     Dim hKey&       ' Return handle to opened key
  577.     Dim lLenValueName&
  578.     Dim lLenValue&
  579.     Dim lKeyIndx&
  580.     Dim sBinaryString$
  581.     Dim Item As ListItem
  582.     Dim iTempInt%
  583.  
  584.     '---------------------------
  585.     'values for QueryInfoKey:
  586.     '---------------------------
  587.     Dim sClassName$
  588.     Dim lClassLen&
  589.     Dim lSubKeys&
  590.     Dim lMaxSubKey&
  591.     Dim lMaxClass&
  592.     Dim lValues&
  593.     Dim lMaxValueName&
  594.     Dim lMaxValueData&
  595.     Dim lSecurityDesc&
  596.     Dim strucLastWriteTime As FILETIME
  597.     
  598.     Dim iListWidth%  'Used to set listbox scrollbar
  599.     
  600.     lTempLong = SetCursor(iWaitCursor)
  601.     
  602.     RegEntry.rgeExtractKeys
  603.     
  604.     ' -----------------------------------------------------
  605.     ' Open key
  606.     ' -----------------------------------------------------
  607.     lRtn = RegOpenKeyEx(RegEntry.rgeMainKey, RegEntry.rgeSubKey, 0&, KEY_READ, hKey)
  608.     If lRtn <> ERROR_SUCCESS Then
  609.         If lRtn <> ERROR_ACCESS_DENIED Then
  610.             '---------------------------------------------
  611.             'If access is denied don't do anything
  612.             '---------------------------------------------
  613.             MsgBox RtnRegError(lRtn)
  614.         End If
  615.         RegEntry.rgeClear
  616.         
  617.         ' --------------------------------------------------
  618.         ' No key open, so leave
  619.         ' --------------------------------------------------
  620.         Exit Sub
  621.     End If
  622.    
  623.    ' -----------------------------------------------------
  624.    ' Use RegQueryInfoKey to get the maximum value data info.
  625.    ' -----------------------------------------------------
  626.     sClassName = Space$(255)
  627.     lClassLen = CLng(Len(sClassName))
  628.     lRtn = RegQueryInfoKey(hKey, sClassName, lClassLen, 0&, lSubKeys, lMaxSubKey, lMaxClass, lValues, lMaxValueName, lMaxValueData, lSecurityDesc, strucLastWriteTime)
  629.    
  630.  
  631.     ' -----------------------------------------------------
  632.     ' Enumerate the keys
  633.     ' -----------------------------------------------------
  634.     lKeyIndx = 0&
  635.     Do While lRtn = ERROR_SUCCESS
  636.         sBinaryString = ""
  637.  
  638. '-------------------------------------------------------------------
  639. 'If the enumeration fails due to a buffer over-run, we will loop back
  640. 'to this point with larger buffers.
  641. '-------------------------------------------------------------------
  642. ReTryValueEnumeration:
  643.         
  644.         ' --------------------------------------------------
  645.         ' Set variables
  646.         ' --------------------------------------------------
  647.         RegEntry.rgeEntry = Space$(lMaxValueName + 1)
  648.         lLenValueName = CLng(Len(RegEntry.rgeEntry)) '+ 1
  649.         RegEntry.rgeValue = Space$(lMaxValueData + 1)
  650.         lLenValue = CLng(Len(RegEntry.rgeValue))       '+ 1
  651.  
  652.         
  653.         ' --------------------------------------------------
  654.         ' Call the enumeration function
  655.         ' --------------------------------------------------
  656.         lRtn = RegEnumValue(hKey, lKeyIndx, RegEntry.rgeEntry, lLenValueName, 0&, RegEntry.rgeDataType, ByVal RegEntry.rgeValue, lLenValue)
  657.             
  658.         
  659.         ' --------------------------------------------------
  660.         ' Check for success
  661.         ' --------------------------------------------------
  662.         If lRtn = ERROR_SUCCESS Then
  663.          
  664.             '-----------------------------------------------
  665.             'Add an item to the list box
  666.             '-----------------------------------------------
  667.             Set Item = Form1!ListView1.ListItems.Add()
  668.             
  669.             ' -----------------------------------------------
  670.             ' Start building the entry to put in the list box:
  671.             ' -----------------------------------------------
  672.             RegEntry.rgeEntry = Mid$(RegEntry.rgeEntry, 1, lLenValueName)
  673.         
  674.             ' -----------------------------------------------
  675.             ' Default values don't have a name.
  676.             ' -----------------------------------------------
  677.             If lLenValueName = 0 Then
  678.                 RegEntry.rgeEntry = "(Default)"
  679.             End If
  680.             
  681.             RegEntry.rgeValue = Mid$(RegEntry.rgeValue, 1, lLenValue)
  682.             Select Case RegEntry.rgeDataType
  683.                 Case REG_MULTI_SZ
  684.                     ' --------------------------------------
  685.                     ' REG_MULTI_SZ strings are a series of
  686.                     '   zero terminated strings. If we don't
  687.                     '   strip out the zeros, only the first
  688.                     '   one will display.
  689.                     ' We will replace them with spaces.
  690.                     ' --------------------------------------
  691.                     Item.SmallIcon = 4
  692.                     Do While InStr(RegEntry.rgeValue, Chr$(0))
  693.                         RegEntry.rgeValue = Left$(RegEntry.rgeValue, InStr(RegEntry.rgeValue, Chr$(0)) - 1) & " " & Right$(RegEntry.rgeValue, Len(RegEntry.rgeValue) - InStr(RegEntry.rgeValue, Chr$(0)))
  694.                     Loop
  695.                 Case REG_SZ
  696.                     ' --------------------------------------
  697.                     ' REG_SZ values are zero-terminated
  698.                     '   strings, and are the most common
  699.                     '   values.
  700.                     ' --------------------------------------
  701.                     Item.SmallIcon = 4
  702.                     
  703.                     '---------------------------------------
  704.                     'Put quotes around the string
  705.                     '---------------------------------------
  706.                     RegEntry.rgeValue = """" & Left$(RegEntry.rgeValue, lLenValue - 1) & """"
  707.                 
  708.                 Case REG_EXPAND_SZ
  709.                     '---------------------------------------
  710.                     'Environmental variables that are binary
  711.                     'but evaluate as strings.  Not edited by
  712.                     'this program.
  713.                     '---------------------------------------
  714.                     Item.SmallIcon = 5
  715.                 Case REG_FULL_RESOURCE_DESCRIPTOR
  716.                     ' --------------------------------------
  717.                     ' Resource Descriptors require a special
  718.                     '   editor to properly be displayed or
  719.                     '   edited.
  720.                     ' --------------------------------------
  721.                     Item.SmallIcon = 5
  722.                     RegEntry.rgeValue = "REG_FULL_RESOURCE_DESCRIPTOR"
  723.  
  724.                 Case REG_DWORD
  725.                     ' --------------------------------------
  726.                     ' REG_DWORD values are 32-bit unsigned
  727.                     '   integers
  728.                     ' Tortuous manipulation to make values
  729.                     '   above 7FFFFFFF appear as positive
  730.                     '   values.
  731.                     ' VB Longs would display them as
  732.                     '   negative numbers.
  733.                     ' --------------------------------------
  734.                     Item.SmallIcon = 5
  735.                     fTempDbl = Asc(Mid$(RegEntry.rgeValue, 1, 1)) + &H100& * Asc(Mid$(RegEntry.rgeValue, 2, 1)) + &H10000 * Asc(Mid$(RegEntry.rgeValue, 3, 1)) + &H1000000 * CDbl(Asc(Mid$(RegEntry.rgeValue, 4, 1)))
  736.                     If fTempDbl > &H7FFFFFFF Then
  737.                         RegEntry.rgeValue = "&H" & Hex$(fTempDbl - 4294967296#)
  738.                     Else
  739.                         RegEntry.rgeValue = "&H" & Hex$(fTempDbl)
  740.                     End If
  741.                     RegEntry.rgeValue = RegEntry.rgeValue & " (" & Format$(fTempDbl) & ")"
  742.  
  743.                 Case REG_BINARY
  744.               
  745.                     ' --------------------------------------
  746.                     ' Binary values may be of any length,
  747.                     '   and may represent text or other data.
  748.                     ' They require a special editor to
  749.                     '   modify them.
  750.                     ' --------------------------------------
  751.                     Item.SmallIcon = 5
  752.                     For iTempInt = 1 To Len(RegEntry.rgeValue)
  753.                         sBinaryString = sBinaryString & Format$(Hex(Asc(Mid$(RegEntry.rgeValue, iTempInt, 1))), "00") & " "
  754.                     Next iTempInt
  755.                     RegEntry.rgeValue = sBinaryString
  756.             End Select
  757.  
  758.             If Len(RegEntry.rgeValue) = 0 Then
  759.                 RegEntry.rgeValue = "(value not set)"
  760.             End If
  761.  
  762.          
  763.             ' -----------------------------------------------
  764.             ' Enter the value into the list box
  765.             ' -----------------------------------------------
  766.             Item.Text = RegEntry.rgeEntry
  767.             Item.SubItems(1) = RegEntry.rgeValue
  768.             Item.Tag = CStr(lKeyIndx)
  769.             ' -----------------------------------------------
  770.             ' Increment the key and do it again.
  771.             ' -----------------------------------------------
  772.             lKeyIndx = lKeyIndx + 1
  773.  
  774.         ElseIf lRtn = ERROR_MORE_DATA Then
  775.             ' -----------------------------------------------
  776.             ' This error means that, despite querying the key,
  777.             '   we have not set one of the buffers large
  778.             '   enough.  Increment the buffer sizes and try
  779.             '   again
  780.             ' -----------------------------------------------
  781.             lMaxValueData = lMaxValueData + 5
  782.             lMaxValueName = lMaxValueName + 5
  783.             GoTo ReTryValueEnumeration
  784.  
  785.         ElseIf lRtn = ERROR_NO_MORE_ITEMS Then
  786.             ' -----------------------------------------------
  787.             ' Not an error, just end of list -- exit the
  788.             '   loop
  789.             ' -----------------------------------------------
  790.             lRtn = ERROR_SUCCESS
  791.             Exit Do
  792.  
  793.         Else
  794.             ' --------------------------------------------------
  795.             ' Key still open, so display the error and fall
  796.             '   thru to the close function below
  797.             ' --------------------------------------------------
  798.             MsgBox RtnRegError(lRtn)
  799.             Exit Do
  800.         End If
  801.     Loop
  802.     
  803.     ' -----------------------------------------------------
  804.     ' Always close opened keys!
  805.     ' -----------------------------------------------------
  806.     lRtn = RegCloseKey(hKey)
  807.  
  808. End Sub
  809.  
  810. Public Sub RegGetValue()
  811.     
  812.     '----------------------------------------------------------
  813.     'This Sub is not used by this demo, but it is provided as an
  814.     'encapsulation of the RegQueryValueEx function
  815.     '----------------------------------------------------------
  816.     
  817.     ' --------------------------------------------------------
  818.     ' RegEntry must be pre-filled with a key in rgeSubKey, and
  819.     ' rgeEntry.  This sub will fill the rgeDataType and rgeValue items,
  820.     ' as well as the rgeMainKey if that is not already filled.
  821.     ' --------------------------------------------------------
  822.     Dim lRtn&        'returned by registry functions, should be 0&
  823.     Dim hKey&        'return handle to opened key
  824.     Dim lData&       'length of data in returned string
  825.  
  826.     '------------------------
  827.     'values for QueryInfoKey:
  828.     '------------------------
  829.     Dim sClassName$
  830.     Dim lClassLen&
  831.     Dim lSubKeys&
  832.     Dim lMaxSubKey&
  833.     Dim lMaxClass&
  834.     Dim lValues&
  835.     Dim lMaxValueName&
  836.     Dim lMaxValueData&
  837.     Dim lSecurityDesc&
  838.     Dim strucLastWriteTime As FILETIME
  839.  
  840.       RegEntry.rgeExtractKeys
  841.     
  842.       ' --------------------------------------------------
  843.       ' Open key
  844.       ' --------------------------------------------------
  845.       lRtn = RegOpenKeyEx(RegEntry.rgeMainKey, RegEntry.rgeSubKey, 0&, KEY_READ, hKey)
  846.       If lRtn <> ERROR_SUCCESS Then
  847.           MsgBox RtnRegError(lRtn)
  848.           RegEntry.rgeClear
  849.           Exit Sub          'No key open, so leave
  850.       End If
  851.     
  852.       ' --------------------------------------------------
  853.       'use RegQueryInfoKey to get the maximum value data info.
  854.       ' --------------------------------------------------
  855.       sClassName = Space$(255)
  856.       lClassLen = CLng(Len(sClassName))
  857.       lRtn = RegQueryInfoKey(hKey, sClassName, lClassLen, 0&, lSubKeys, lMaxSubKey, lMaxClass, lValues, lMaxValueName, lMaxValueData, lSecurityDesc, strucLastWriteTime)
  858.       
  859.       ' --------------------------------------------------
  860.       ' Set up buffer for data to be returned in.
  861.       ' --------------------------------------------------
  862.       RegEntry.rgeValue = Space$(lMaxValueName + 1)
  863.       lData = Len(RegEntry.rgeValue)
  864.       
  865.       ' --------------------------------------------------
  866.       ' Read key
  867.       ' --------------------------------------------------
  868.       lRtn = RegQueryValueEx(hKey, RegEntry.rgeEntry, 0&, RegEntry.rgeDataType, RegEntry.rgeValue, lData)
  869.       If lRtn <> ERROR_SUCCESS Then
  870.           ' -----------------------------------------------
  871.           ' Key still open, so finish up
  872.           ' -----------------------------------------------
  873.           MsgBox RtnRegError(lRtn)
  874.           RegEntry.rgeClear
  875.       End If
  876.  
  877.  
  878.       ' --------------------------------------------------
  879.       ' Always close opened keys!
  880.       ' --------------------------------------------------
  881.       lRtn = RegCloseKey(hKey)
  882.    
  883. End Sub
  884.  
  885. Sub RegSetValue()
  886.     ' --------------------------------------------------------
  887.     ' DWORD Values must be in Hex form for this function to
  888.     '   work.
  889.     ' --------------------------------------------------------
  890.     Dim lRtn&            'returned by registry functions, should be 0&
  891.     Dim hKey&         'return handle to opened key
  892.     Dim iFirstChar%
  893.     Dim iSecondChar%
  894.     Dim iThirdChar%
  895.     Dim iFourthChar%
  896.     
  897.     If RegEntry.rgeDataType <> REG_SZ And RegEntry.rgeDataType <> REG_DWORD Then
  898.         MsgBox "This demo only supports writing keys of the types REG_SZ and REG_DWORD.  This key uses a different type."
  899.         Exit Sub
  900.     End If
  901.     
  902.     ' -----------------------------------------------------
  903.     ' Check rgeMainKey for validity
  904.     ' -----------------------------------------------------
  905.     If RegEntry.rgeMainKey >= &H80000000 And RegEntry.rgeMainKey <= &H80000006 Then
  906.  
  907.         ' -----------------------------------------------------
  908.         ' Open key
  909.         ' -----------------------------------------------------
  910.         lRtn = RegOpenKeyEx(RegEntry.rgeMainKey, RegEntry.rgeSubKey, 0&, KEY_WRITE, hKey)
  911.         If lRtn <> ERROR_SUCCESS Then
  912.             MsgBox RtnRegError(lRtn)
  913.             RegEntry.rgeClear
  914.             Exit Sub       'No key open, so leave
  915.         End If
  916.       
  917.         ' -----------------------------------------------------
  918.         ' Write new RegEntry.rgeValue to key
  919.         ' -----------------------------------------------------
  920.         If RegEntry.rgeDataType = REG_DWORD Then
  921.             RegEntry.rgeValue = Left(Trim(RegEntry.rgeValue), 8)
  922.             If Left$(RegEntry.rgeValue, 2) <> "&H" Then
  923.             RegEntry.rgeValue = "&H" & Left(Trim(RegEntry.rgeValue), 8)
  924.             End If
  925.             If Len(RegEntry.rgeValue) <= 6 Then
  926.             RegEntry.rgeValue = RegEntry.rgeValue & "&"
  927.             End If
  928.         
  929.             ' -----------------------------------------------------
  930.                 'Convert number string to 32-bit DWORD and save:
  931.             ' -----------------------------------------------------
  932.             lRtn = RegSetValueEx(hKey, RegEntry.rgeEntry, 0&, RegEntry.rgeDataType, CLng(Val(RegEntry.rgeValue)), 4&)
  933.         Else
  934.  
  935.             ' -----------------------------------------------------
  936.                 'Save type REG_SZ (strings)
  937.             ' -----------------------------------------------------
  938.             lRtn = RegSetValueEx(hKey, RegEntry.rgeEntry, 0&, RegEntry.rgeDataType, ByVal RegEntry.rgeValue, CLng(Len(RegEntry.rgeValue)))
  939.         End If
  940.         If lRtn <> ERROR_SUCCESS Then
  941.             MsgBox RtnRegError(lRtn) 'Key still open, so finish up
  942.         End If
  943.         ' -----------------------------------------------------
  944.         ' Always close opened keys!
  945.         ' -----------------------------------------------------
  946.         lRtn = RegCloseKey(hKey)
  947.     End If
  948. End Sub
  949.  
  950. Private Function RtnRegError$(errorcode&)
  951.     Select Case errorcode
  952.         Case 1009, 1015
  953.             ' -----------------------------------------------------
  954.                 'We're in trouble now
  955.             ' -----------------------------------------------------
  956.             RtnRegError = "The Registry Database is corrupt!"
  957.         Case 2, 1010
  958.             RtnRegError = "Bad Key Name!"
  959.         Case 1011
  960.             RtnRegError = "Can't Open Key"
  961.         Case 4, 1012
  962.             RtnRegError = "Can't Read Key"
  963.         Case 5
  964.             RtnRegError = "Access to this key is denied."
  965.         Case 1013
  966.             RtnRegError = "Can't Write Key"
  967.         Case 8, 14
  968.             RtnRegError = "Out of memory"
  969.         Case 87
  970.             RtnRegError = "Invalid Parameter"
  971.         Case 234
  972.             RtnRegError = "Error - There is more data than the buffer can handle!"
  973.         Case Else
  974.             RtnRegError = "Undefined Key Error Code" & Str$(errorcode) & "!"
  975.     End Select
  976. End Function
  977.  
  978. Function WordLo(lLongIn&) As Integer
  979.     If (lLongIn And &HFFFF&) > &H7FFF Then
  980.         WordLo = (lLongIn And &HFFFF&) - &H10000
  981.     Else
  982.         WordLo = lLongIn And &HFFFF&
  983.     End If
  984. End Function
  985.  
  986.